package com.common.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 反射工具类
* @ClassName: ReflectionUtils 
* @Description: TODO(这里用一句话描述这个类的作用) 
* @author feilun
* @date 2016年8月23日 下午5:22:09 
*
 */
public class QPReflectionUtils {
	public static final String CGLIB_CLASS_SEPARATOR = "$$";
	private static Logger logger = LoggerFactory.getLogger(QPReflectionUtils.class);

	public static Object invokeGetterMethod(Object obj, String propertyName) {
		String getterMethodName = "get" + StringUtils.capitalize(propertyName);
		return invokeMethod(obj, getterMethodName, new Class[0], new Object[0]);
	}

	public static void invokeSetterMethod(Object obj, String propertyName,Object value) {
		invokeSetterMethod(obj, propertyName, value, null);
	}

	public static Object convertStringToObject(String value, Class<?> toType) {
		try {
			return ConvertUtils.convert(value, toType);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	public static void invokeSetterMethod(Object obj, String propertyName,Object value, Class<?> propertyType) {
		Class type = propertyType != null ? propertyType : value.getClass();
		String setterMethodName = "set" + StringUtils.capitalize(propertyName);
		invokeMethod(obj, setterMethodName, new Class[] { type },
				new Object[] { value });
	}

	public static void setFieldValue(Object obj, String fieldName, Object value) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field ["
					+ fieldName + "] on target [" + obj + "]");
		}
		try {
			field.set(obj, value);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	public static Field getAccessibleField(Object obj, String fieldName) {
		for (Class superClass = obj.getClass(); superClass != Object.class;) {
			try {
				Field field = superClass.getDeclaredField(fieldName);
				field.setAccessible(true);
				return field;
			} catch (NoSuchFieldException localNoSuchFieldException) {
				superClass = superClass.getSuperclass();
			}
		}
		return null;
	}

	public static Class<?> getUserClass(Class<?> clazz) {
		if ((clazz != null) && (clazz.getName().contains("$$"))) {
			Class superClass = clazz.getSuperclass();
			if ((superClass != null) && (!Object.class.equals(superClass))) {
				return superClass;
			}
		}
		return clazz;
	}

	public static Object invokeMethod(Object obj, String methodName,
			Class<?>[] parameterTypes, Object[] args) {
		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
		if (method == null) {
			throw new IllegalArgumentException("Could not find method ["
					+ methodName + "] on target [" + obj + "]");
		}
		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	public static Method getAccessibleMethod(Object obj, String methodName,
			Class<?>[] parameterTypes) {
		for (Class superClass = obj.getClass(); superClass != Object.class;) {
			try {
				Method method = superClass.getDeclaredMethod(methodName,
						parameterTypes);

				method.setAccessible(true);

				return method;
			} catch (NoSuchMethodException localNoSuchMethodException) {
				superClass = superClass.getSuperclass();
			}
		}

		return null;
	}

	public static <T> Class<T> getSuperClassGenricType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	public static Class getSuperClassGenricType(Class clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			logger.warn(clazz.getSimpleName()+ "'s superclass not ParameterizedType");
			return Object.class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if ((index >= params.length) || (index < 0)) {
			logger.warn("Index: " + index + ", Size of "+ clazz.getSimpleName() + "'s Parameterized Type: "+ params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			logger.warn(clazz.getSimpleName()+ " not set the actual class on superclass generic parameter");
			return Object.class;
		}

		return (Class) params[index];
	}

	public static RuntimeException convertReflectionExceptionToUnchecked(
			Exception e) {
		if (((e instanceof IllegalAccessException))
				|| ((e instanceof IllegalArgumentException))
				|| ((e instanceof NoSuchMethodException)))
			return new IllegalArgumentException("Reflection Exception.", e);
		if ((e instanceof InvocationTargetException))
			return new RuntimeException("Reflection Exception.",((InvocationTargetException) e).getTargetException());
		if ((e instanceof RuntimeException)) {
			return (RuntimeException) e;
		}
		return new RuntimeException("Unexpected Checked Exception.", e);
	}
	//================================================================================================
	
	
	/** 
     * 利用反射获取指定对象的指定属性 
     * @param obj 目标对象 
     * @param fieldName 目标属性 
     * @return 目标属性的值 
     */  
    public static Object getFieldValue(Object obj, String fieldName) {  
        Object result = null;  
        Field field = getField(obj, fieldName);  
        if (field != null) {  
           field.setAccessible(true);  
           try {  
               result = field.get(obj);  
           } catch (IllegalArgumentException e) {  
               // TODO Auto-generated catch block  
               e.printStackTrace();  
           } catch (IllegalAccessException e) {  
               // TODO Auto-generated catch block  
               e.printStackTrace();  
           }  
        }  
        return result;  
    }
	
	/** 
     * 利用反射获取指定对象里面的指定属性 
     * @param obj 目标对象 
     * @param fieldName 目标属性 
     * @return 目标字段 
     */  
    private static Field getField(Object obj, String fieldName) {  
        Field field = null;  
       for (Class<?> clazz=obj.getClass(); clazz != Object.class; clazz=clazz.getSuperclass()) {  
           try {  
               field = clazz.getDeclaredField(fieldName);  
               break;  
           } catch (NoSuchFieldException e) {  
               //这里不用做处理，子类没有该字段可能对应的父类有，都没有就返回null。  
           }  
        }  
        return field;  
    }
    /** 
     * 利用反射设置指定对象的指定属性为指定的值 
     * @param obj 目标对象 
     * @param fieldName 目标属性 
      * @param fieldValue 目标值 
     */  
    public static void setFieldValue(Object obj,String fieldName,String fieldValue) {  
    	Field field = getField(obj, fieldName);  
        if (field != null) {  
           try {  
               field.setAccessible(true);
               field.set(obj, fieldValue);
           } catch (IllegalArgumentException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();  
           } catch (IllegalAccessException e) {
               // TODO Auto-generated catch block  
               e.printStackTrace();  
           }  
        }
    }  
    
    /**
     * 实体转成map
    * @Title: entityToMapWithPage 
    * @Description: TODO(这里用一句话描述这个方法的作用)
    * @author feilun 
    * @param @param obj
    * @param @param page
    * @param @return
    * @return Map<String,String>
    * @throws
     */
    public static Map<String,Object> entityToMapWithPage(Object obj) {
    	Map<String,Object> map = new HashMap<String, Object>();
    	Class<?> clazz = obj.getClass();
		Field[] fields = obj.getClass().getDeclaredFields();//获得属性
	    for (Field field : fields) {
	    	PropertyDescriptor pd;
			try {
				pd = new PropertyDescriptor(field.getName(),clazz);
				Method getMethod = pd.getReadMethod();//获得get方法
				try {
					Object value = getMethod.invoke(obj);
					//if(null != value){
					String type = field.getType().getName();
					map.put(field.getName(), value==null?null:value);
					//}
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			} catch (IntrospectionException e1) {
				e1.printStackTrace();
			}
	    }
		return map;
	}
    
}